package il.ac.tau.cg.ex3.math.intersectors;

import il.ac.tau.cg.ex3.entities.surfaces.Surface;
import il.ac.tau.cg.ex3.math.Point;
import il.ac.tau.cg.ex3.math.Vector;
import il.ac.tau.cg.ex3.math.shapes.Box;
import il.ac.tau.cg.ex3.math.shapes.Intersectable;
import il.ac.tau.cg.ex3.utils.octree.BoundingBox;
import il.ac.tau.cg.ex3.utils.octree.Octree;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class OctreeIntersector extends Intersector
{
	private Octree<Surface> octree;
	
	public OctreeIntersector(BoundingBox boundingBox)
	{
		octree = new Octree<Surface>(boundingBox);
	}
	
	public void insert(Surface surface)
	{
		octree.insert(surface);
	}
	
	public void insert(Collection<? extends Surface> surfaces)
	{
		octree.insert(surfaces);
	}
	
	@Override
	public IntersectionResult intersect(Point origin, Vector direction)
	{
		List<Intersectable> intersectables = collectPotentialIntersectables(origin, direction, octree);
		
		return intersectCollection(origin, direction, intersectables);
	}
	
	private List<Intersectable> collectPotentialIntersectables(Point origin, Vector direction, Octree<Surface> octree)
	{
		BoundingBox boundingBox = octree.getBoundingBox();
		
		Point p0 = new Point(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ());
		Point p1 = new Point(boundingBox.getMaxX(), boundingBox.getMinY(), boundingBox.getMinZ());
		Point p2 = new Point(boundingBox.getMinX(), boundingBox.getMaxY(), boundingBox.getMinZ());
		Point p3 = new Point(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMaxZ());
		
		Box box = new Box(p0, p1, p2, p3);
		
		if (box.intersect(origin, direction).isEmpty())
		{
			return new ArrayList<Intersectable>();
		}
		
		List<Intersectable> items = new ArrayList<Intersectable>(octree.getItems());
		
		for (int x = 0; x < 2; x++)
		{
			for (int y = 0; y < 2; y++)
			{
				for (int z = 0; z < 2; z++)
				{
					Octree<Surface> subtree = octree.getSubtree(x, y, z);
					
					if (subtree != null)
					{
						items.addAll(collectPotentialIntersectables(origin, direction, subtree));
					}
				}
			}
		}
		
		return items;
	}
}
